#include <stdlib.h>

typedef int row3_t[3];
typedef row3_t array4_3_t[5];

array4_3_t A;

int get_value(array4_3_t A, long i, long j)
{
    return A[i][j];
}

row3_t row0, row1, row2, row3;
int *B[4] = {row0, row1, row2, row3};

int get_value2(long *B[4], long i, long  j)
{
    return B[i][j];
}

/* $begin 350-fixmatrixdef-c */
#define N 16
typedef int fix_matrix[N][N];
/* $end 350-fixmatrixdef-c */

fix_matrix *new_fix_matrix(long n) {
    return (fix_matrix *) malloc(sizeof(fix_matrix));
}

/* $begin 350-fixprodele-c */
/* Compute i,k of fixed matrix product */
int fix_prod_ele (fix_matrix A, fix_matrix B, long i, long k) {
    long j;
    int result = 0;

    for (j = 0; j < N; j++)
	result += A[i][j] * B[j][k];

    return result;
}
/* $end 350-fixprodele-c */

/* $begin 350-fixprodeleopt-c */
/* Compute i,k of fixed matrix product */
int fix_prod_ele_opt(fix_matrix A, fix_matrix B, long i, long k) {
    int *Aptr = &A[i][0];    /* Points to elements in row i of A    */ // line:asm:fixprodele:c:aptr
    int *Bptr = &B[0][k];    /* Points to elements in column k of B */
    int *Bend = &B[N][k];    /* Marks stopping point for Bptr       */ // line:asm:fixprodele:c:bend
    int result = 0;
    do {                          /* No need for initial test */
	result += *Aptr * *Bptr;  /* Add next product to sum  */
	Aptr ++;                  /* Move Aptr to next column */
	Bptr += N;                /* Move Bptr to next row    */
    } while (Bptr != Bend);       /* Test for stopping point  */
    return result;
}
/* $end 350-fixprodeleopt-c */

/* $begin 350-fixdiag-c */
/* Set all diagonal elements to val */
void fix_set_diag(fix_matrix A, int val) {
    long i;
    for (i = 0; i < N; i++)
	A[i][i] = val;
}
/* $end 350-fixdiag-c */

/* $begin 350-fixdiagopt-c */
/* Set all diagonal elements to val */
void fix_set_diag_opt(fix_matrix A, int val) {
    int *Abase = &A[0][0];
    long i = 0;
    long iend = N*(N+1);
    do {
	Abase[i] = val;
	i += (N+1);
    } while (i != iend);
}
/* $end 350-fixdiagopt-c */

int fix_ele(fix_matrix A, int i, int j) {
    return A[i][j];
}

/* $begin 350-newvarmatrix-c */
void *new_var_matrix(long n) {
    return malloc(sizeof(int[n][n]));
}
/* $end 350-newvarmatrix-c */

/* $begin 350-varele-c */
int var_ele(long n, int A[n][n], long i, long j) {
    return A[i][j];
}
/* $end 350-varele-c */

/* Demonstrate how you would access a matrix generated by malloc */
int pvar_ele(long n, void *p, long i, long j) {
    return var_ele(n, p, i, j);
}

/* $begin 350-varprodele-c */
/* Compute i,k of variable matrix product */
int var_prod_ele(long n, int A[n][n], int B[n][n], long i, long k) {
    long j;
    int result = 0;

    for (j = 0; j < n; j++)
	result += A[i][j] * B[j][k]; //line:asm:array:varprodaccess

    return result;
}
/* $end 350-varprodele-c */

/* $begin 350-varprodeleopt-c */
/* Compute i,k of variable matrix product */
int var_prod_ele_opt(long n, int A[n][n], int B[n][n], long i, long k) {
    int *Arow = A[i];
    int *Bptr = &B[0][k];
    int result = 0;
    long j;
    for (j = 0; j < n; j++) {
        result += Arow[j] * *Bptr;
	Bptr += n;
    }
    return result;
}
/* $end 350-varprodeleopt-c */

